package net.lanelife.casino.caipiao.service.award;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import net.lanelife.casino.caipiao.entity.BetRecord;
import net.lanelife.casino.caipiao.entity.GameType;
import net.lanelife.casino.caipiao.entity.LotteryNumber;
import net.lanelife.casino.caipiao.entity.User;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * 注单分组
 * @author Lane
 *
 */
public class BetGroup {
	
	private static final Log LOGGER = LogFactory.getLog(BetGroup.class);
	
	private static ExecutorService pool = Executors.newFixedThreadPool(100);
	
	private List<BetGroup.Member> members = new ArrayList<BetGroup.Member>();
	
	public static enum Status {
		SUCCESS, FAILURE
	}
	
	public static BetGroup grouping(List<BetRecord> betRecords) {
		BetGroup group = new BetGroup();
		Map<Integer, List<BetRecord>> map = new HashMap<Integer, List<BetRecord>>();
		for (BetRecord br : betRecords) {
			List<BetRecord> brs = map.get(br.getUserId());
			if (brs == null) {
				brs = new ArrayList<BetRecord>();
				map.put(br.getUserId(), brs);
				BetGroup.Member member = group.new Member(new User(br.getUserId(), br.getUserName()), brs);
				group.members.add(member);
			}
			brs.add(br);
		}
		return group;
	}
	
	public static void award(final BetGroupAwarder awarder, final GameType gameType, final LotteryNumber lotteryNumber, final BetGroup group) throws Exception {
		final CountDownLatch latch = new CountDownLatch(group.members.size());
		for (final BetGroup.Member member : group.members) {
			pool.execute(new Runnable() {
				public void run() {
					try {
						//成功状态交与派奖器设定，单个注单失败不能影响该用户所有注单
						awarder.award(member, lotteryNumber);
						//member.setStatus(BetGroup.Status.SUCCESS);
						if (member.getStatus() == BetGroup.Status.SUCCESS) {
							LOGGER.info(String.format("%s[%s] 单一用户派奖完成：[用户ID：%d，用户帐号：%s, 注单数：%d]", gameType.getName(), lotteryNumber.getIssue(), member.getUser().getId(), member.getUser().getUserName(), member.getBetRecords().size()));
						}
					} catch (Exception e) {
						member.setStatus(BetGroup.Status.FAILURE);
						LOGGER.error(String.format("%s[%s] 单一用户派奖发生异常：[用户ID：%d，用户帐号：%s, 注单数：%d，异常信息：%s]", gameType.getName(), lotteryNumber.getIssue(), member.getUser().getId(), member.getUser().getUserName(), member.getBetRecords().size(), e.getMessage()));
					} finally {
						latch.countDown();
					}
				}
			});
		}
		latch.await();
		if (!group.success()) {
			throw new RuntimeException("分组派奖任务未全部完成！");
		}
	}
	
	public Boolean success() {
		for (BetGroup.Member member : this.members) {
			if (member.getStatus() == BetGroup.Status.FAILURE) {
				return Boolean.FALSE;
			}
		}
		return Boolean.TRUE;
	}
	
	class Member {
		
		private User user;
		
		private List<BetRecord> betRecords;
		
		private Status status = BetGroup.Status.FAILURE;
		
		public Member(User user, List<BetRecord> betRecords) {
			this.user = user;
			this.betRecords = betRecords;
		}

		public User getUser() {
			return user;
		}

		public void setUser(User user) {
			this.user = user;
		}

		public List<BetRecord> getBetRecords() {
			return betRecords;
		}

		public void setBetRecords(List<BetRecord> betRecords) {
			this.betRecords = betRecords;
		}

		public Status getStatus() {
			return status;
		}

		public void setStatus(Status status) {
			this.status = status;
		}

		
	}

}
